home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / g_utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  11.4 KB  |  571 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // g_utils.c -- misc utility functions for game module
  21.  
  22. #include "g_local.h"
  23.  
  24.  
  25. void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
  26. {
  27.     result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
  28.     result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
  29.     result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
  30. }
  31.  
  32.  
  33. /*
  34. =============
  35. G_Find
  36.  
  37. Searches all active entities for the next one that holds
  38. the matching string at fieldofs (use the FOFS() macro) in the structure.
  39.  
  40. Searches beginning at the edict after from, or the beginning if NULL
  41. NULL will be returned if the end of the list is reached.
  42.  
  43. =============
  44. */
  45. edict_t *G_Find (edict_t *from, int fieldofs, char *match)
  46. {
  47.     char    *s;
  48.  
  49.     if (!from)
  50.         from = g_edicts;
  51.     else
  52.         from++;
  53.  
  54.     for ( ; from < &g_edicts[globals.num_edicts] ; from++)
  55.     {
  56.         if (!from->inuse)
  57.             continue;
  58.         s = *(char **) ((byte *)from + fieldofs);
  59.         if (!s)
  60.             continue;
  61.         if (!Q_stricmp (s, match))
  62.             return from;
  63.     }
  64.  
  65.     return NULL;
  66. }
  67.  
  68.  
  69. /*
  70. =================
  71. findradius
  72.  
  73. Returns entities that have origins within a spherical area
  74.  
  75. findradius (origin, radius)
  76. =================
  77. */
  78. edict_t *findradius (edict_t *from, vec3_t org, float rad)
  79. {
  80.     vec3_t    eorg;
  81.     int        j;
  82.  
  83.     if (!from)
  84.         from = g_edicts;
  85.     else
  86.         from++;
  87.     for ( ; from < &g_edicts[globals.num_edicts]; from++)
  88.     {
  89.         if (!from->inuse)
  90.             continue;
  91.         if (from->solid == SOLID_NOT)
  92.             continue;
  93.         for (j=0 ; j<3 ; j++)
  94.             eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);
  95.         if (VectorLength(eorg) > rad)
  96.             continue;
  97.         return from;
  98.     }
  99.  
  100.     return NULL;
  101. }
  102.  
  103.  
  104. /*
  105. =============
  106. G_PickTarget
  107.  
  108. Searches all active entities for the next one that holds
  109. the matching string at fieldofs (use the FOFS() macro) in the structure.
  110.  
  111. Searches beginning at the edict after from, or the beginning if NULL
  112. NULL will be returned if the end of the list is reached.
  113.  
  114. =============
  115. */
  116. #define MAXCHOICES    8
  117.  
  118. edict_t *G_PickTarget (char *targetname)
  119. {
  120.     edict_t    *ent = NULL;
  121.     int        num_choices = 0;
  122.     edict_t    *choice[MAXCHOICES];
  123.  
  124.     if (!targetname)
  125.     {
  126.         gi.dprintf("G_PickTarget called with NULL targetname\n");
  127.         return NULL;
  128.     }
  129.  
  130.     while(1)
  131.     {
  132.         ent = G_Find (ent, FOFS(targetname), targetname);
  133.         if (!ent)
  134.             break;
  135.         choice[num_choices++] = ent;
  136.         if (num_choices == MAXCHOICES)
  137.             break;
  138.     }
  139.  
  140.     if (!num_choices)
  141.     {
  142.         gi.dprintf("G_PickTarget: target %s not found\n", targetname);
  143.         return NULL;
  144.     }
  145.  
  146.     return choice[rand() % num_choices];
  147. }
  148.  
  149.  
  150.  
  151. void Think_Delay (edict_t *ent)
  152. {
  153.     G_UseTargets (ent, ent->activator);
  154.     G_FreeEdict (ent);
  155. }
  156.  
  157. /*
  158. ==============================
  159. G_UseTargets
  160.  
  161. the global "activator" should be set to the entity that initiated the firing.
  162.  
  163. If self.delay is set, a DelayedUse entity will be created that will actually
  164. do the SUB_UseTargets after that many seconds have passed.
  165.  
  166. Centerprints any self.message to the activator.
  167.  
  168. Search for (string)targetname in all entities that
  169. match (string)self.target and call their .use function
  170.  
  171. ==============================
  172. */
  173. void G_UseTargets (edict_t *ent, edict_t *activator)
  174. {
  175.     edict_t        *t;
  176.  
  177. //
  178. // check for a delay
  179. //
  180.     if (ent->delay)
  181.     {
  182.     // create a temp object to fire at a later time
  183.         t = G_Spawn();
  184.         t->classname = "DelayedUse";
  185.         t->nextthink = level.time + ent->delay;
  186.         t->think = Think_Delay;
  187.         t->activator = activator;
  188.         if (!activator)
  189.             gi.dprintf ("Think_Delay with no activator\n");
  190.         t->message = ent->message;
  191.         t->target = ent->target;
  192.         t->killtarget = ent->killtarget;
  193.         return;
  194.     }
  195.     
  196.     
  197. //
  198. // print the message
  199. //
  200.     if ((ent->message) && !(activator->svflags & SVF_MONSTER))
  201.     {
  202.         gi.centerprintf (activator, "%s", ent->message);
  203.         if (ent->noise_index)
  204.             gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);
  205.         else
  206.             gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  207.     }
  208.  
  209. //
  210. // kill killtargets
  211. //
  212.     if (ent->killtarget)
  213.     {
  214.         t = NULL;
  215.         while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))
  216.         {
  217.             G_FreeEdict (t);
  218.             if (!ent->inuse)
  219.             {
  220.                 gi.dprintf("entity was removed while using killtargets\n");
  221.                 return;
  222.             }
  223.         }
  224.     }
  225.  
  226. //    gi.dprintf("TARGET: activating %s\n", ent->target);
  227.  
  228. //
  229. // fire targets
  230. //
  231.     if (ent->target)
  232.     {
  233.         t = NULL;
  234.         while ((t = G_Find (t, FOFS(targetname), ent->target)))
  235.         {
  236.             // doors fire area portals in a specific way
  237.             if (!Q_stricmp(t->classname, "func_areaportal") &&
  238.                 (!Q_stricmp(ent->classname, "func_door") || !Q_stricmp(ent->classname, "func_door_rotating")))
  239.                 continue;
  240.  
  241.             if (t == ent)
  242.             {
  243.                 gi.dprintf ("WARNING: Entity used itself.\n");
  244.             }
  245.             else
  246.             {
  247.                 if (t->use)
  248.                     t->use (t, ent, activator);
  249.             }
  250.             if (!ent->inuse)
  251.             {
  252.                 gi.dprintf("entity was removed while using targets\n");
  253.                 return;
  254.             }
  255.         }
  256.     }
  257. }
  258.  
  259.  
  260. /*
  261. =============
  262. TempVector
  263.  
  264. This is just a convenience function
  265. for making temporary vectors for function calls
  266. =============
  267. */
  268. float    *tv (float x, float y, float z)
  269. {
  270.     static    int        index;
  271.     static    vec3_t    vecs[8];
  272.     float    *v;
  273.  
  274.     // use an array so that multiple tempvectors won't collide
  275.     // for a while
  276.     v = vecs[index];
  277.     index = (index + 1)&7;
  278.  
  279.     v[0] = x;
  280.     v[1] = y;
  281.     v[2] = z;
  282.  
  283.     return v;
  284. }
  285.  
  286.  
  287. /*
  288. =============
  289. VectorToString
  290.  
  291. This is just a convenience function
  292. for printing vectors
  293. =============
  294. */
  295. char    *vtos (vec3_t v)
  296. {
  297.     static    int        index;
  298.     static    char    str[8][32];
  299.     char    *s;
  300.  
  301.     // use an array so that multiple vtos won't collide
  302.     s = str[index];
  303.     index = (index + 1)&7;
  304.  
  305.     Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
  306.  
  307.     return s;
  308. }
  309.  
  310.  
  311. vec3_t VEC_UP        = {0, -1, 0};
  312. vec3_t MOVEDIR_UP    = {0, 0, 1};
  313. vec3_t VEC_DOWN        = {0, -2, 0};
  314. vec3_t MOVEDIR_DOWN    = {0, 0, -1};
  315.  
  316. void G_SetMovedir (vec3_t angles, vec3_t movedir)
  317. {
  318.     if (VectorCompare (angles, VEC_UP))
  319.     {
  320.         VectorCopy (MOVEDIR_UP, movedir);
  321.     }
  322.     else if (VectorCompare (angles, VEC_DOWN))
  323.     {
  324.         VectorCopy (MOVEDIR_DOWN, movedir);
  325.     }
  326.     else
  327.     {
  328.         AngleVectors (angles, movedir, NULL, NULL);
  329.     }
  330.  
  331.     VectorClear (angles);
  332. }
  333.  
  334.  
  335. float vectoyaw (vec3_t vec)
  336. {
  337.     float    yaw;
  338.     
  339.     if (/* vec[YAW] == 0 && */ vec[PITCH] == 0) 
  340.     {
  341.         yaw = 0;
  342.         if (vec[YAW] > 0)
  343.             yaw = 90;
  344.         else if (vec[YAW] < 0)
  345.             yaw = -90;
  346.     }
  347.     else
  348.     {
  349.         yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
  350.         if (yaw < 0)
  351.             yaw += 360;
  352.     }
  353.  
  354.     return yaw;
  355. }
  356.  
  357.  
  358. void vectoangles (vec3_t value1, vec3_t angles)
  359. {
  360.     float    forward;
  361.     float    yaw, pitch;
  362.     
  363.     if (value1[1] == 0 && value1[0] == 0)
  364.     {
  365.         yaw = 0;
  366.         if (value1[2] > 0)
  367.             pitch = 90;
  368.         else
  369.             pitch = 270;
  370.     }
  371.     else
  372.     {
  373.         if (value1[0])
  374.             yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
  375.         else if (value1[1] > 0)
  376.             yaw = 90;
  377.         else
  378.             yaw = -90;
  379.         if (yaw < 0)
  380.             yaw += 360;
  381.  
  382.         forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
  383.         pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
  384.         if (pitch < 0)
  385.             pitch += 360;
  386.     }
  387.  
  388.     angles[PITCH] = -pitch;
  389.     angles[YAW] = yaw;
  390.     angles[ROLL] = 0;
  391. }
  392.  
  393. char *G_CopyString (char *in)
  394. {
  395.     char    *out;
  396.     
  397.     out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);
  398.     strcpy (out, in);
  399.     return out;
  400. }
  401.  
  402.  
  403. void G_InitEdict (edict_t *e)
  404. {
  405.     e->inuse = true;
  406.     e->classname = "noclass";
  407.     e->gravity = 1.0;
  408.     e->s.number = e - g_edicts;
  409. }
  410.  
  411. /*
  412. =================
  413. G_Spawn
  414.  
  415. Either finds a free edict, or allocates a new one.
  416. Try to avoid reusing an entity that was recently freed, because it
  417. can cause the client to think the entity morphed into something else
  418. instead of being removed and recreated, which can cause interpolated
  419. angles and bad trails.
  420. =================
  421. */
  422. edict_t *G_Spawn (void)
  423. {
  424.     int            i;
  425.     edict_t        *e;
  426.  
  427.     e = &g_edicts[(int)maxclients->value+1];
  428.     for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
  429.     {
  430.         // the first couple seconds of server time can involve a lot of
  431.         // freeing and allocating, so relax the replacement policy
  432.         if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
  433.         {
  434.             G_InitEdict (e);
  435.             return e;
  436.         }
  437.     }
  438.     
  439.     if (i == game.maxentities)
  440.         gi.error ("ED_Alloc: no free edicts");
  441.         
  442.     globals.num_edicts++;
  443.     G_InitEdict (e);
  444.     return e;
  445. }
  446.  
  447. /*
  448. =================
  449. G_FreeEdict
  450.  
  451. Marks the edict as free
  452. =================
  453. */
  454. void G_FreeEdict (edict_t *ed)
  455. {
  456.     gi.unlinkentity (ed);        // unlink from world
  457.  
  458.     if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))
  459.     {
  460. //        gi.dprintf("tried to free special edict\n");
  461.         return;
  462.     }
  463.  
  464.     memset (ed, 0, sizeof(*ed));
  465.     ed->classname = "freed";
  466.     ed->freetime = level.time;
  467.     ed->inuse = false;
  468. }
  469.  
  470.  
  471. /*
  472. ============
  473. G_TouchTriggers
  474.  
  475. ============
  476. */
  477. void    G_TouchTriggers (edict_t *ent)
  478. {
  479.     int            i, num;
  480.     edict_t        *touch[MAX_EDICTS], *hit;
  481.  
  482.     // dead things don't activate triggers!
  483.     if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
  484.         return;
  485.  
  486.     num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  487.         , MAX_EDICTS, AREA_TRIGGERS);
  488.  
  489.     // be careful, it is possible to have an entity in this
  490.     // list removed before we get to it (killtriggered)
  491.     for (i=0 ; i<num ; i++)
  492.     {
  493.         hit = touch[i];
  494.         if (!hit->inuse)
  495.             continue;
  496.         if (!hit->touch)
  497.             continue;
  498.         hit->touch (hit, ent, NULL, NULL);
  499.     }
  500. }
  501.  
  502. /*
  503. ============
  504. G_TouchSolids
  505.  
  506. Call after linking a new trigger in during gameplay
  507. to force all entities it covers to immediately touch it
  508. ============
  509. */
  510. void    G_TouchSolids (edict_t *ent)
  511. {
  512.     int            i, num;
  513.     edict_t        *touch[MAX_EDICTS], *hit;
  514.  
  515.     num = gi.BoxEdicts (ent->absmin, ent->absmax, touch
  516.         , MAX_EDICTS, AREA_SOLID);
  517.  
  518.     // be careful, it is possible to have an entity in this
  519.     // list removed before we get to it (killtriggered)
  520.     for (i=0 ; i<num ; i++)
  521.     {
  522.         hit = touch[i];
  523.         if (!hit->inuse)
  524.             continue;
  525.         if (ent->touch)
  526.             ent->touch (hit, ent, NULL, NULL);
  527.         if (!ent->inuse)
  528.             break;
  529.     }
  530. }
  531.  
  532.  
  533.  
  534.  
  535. /*
  536. ==============================================================================
  537.  
  538. Kill box
  539.  
  540. ==============================================================================
  541. */
  542.  
  543. /*
  544. =================
  545. KillBox
  546.  
  547. Kills all entities that would touch the proposed new positioning
  548. of ent.  Ent should be unlinked before calling this!
  549. =================
  550. */
  551. qboolean KillBox (edict_t *ent)
  552. {
  553.     trace_t        tr;
  554.  
  555.     while (1)
  556.     {
  557.         tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
  558.         if (!tr.ent)
  559.             break;
  560.  
  561.         // nail it
  562.         T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
  563.  
  564.         // if we didn't kill it, fail
  565.         if (tr.ent->solid)
  566.             return false;
  567.     }
  568.  
  569.     return true;        // all clear
  570. }
  571.